// pairs.cpp -- defining and using a Pair template
//#include <iostream>
//#include <string>
//
//template <class T1, class T2>
//class Pair
//{
//private:
//	T1 a;
//	T2 b;
//public:
//	T1& first();
//	T2& second();
//	T1 first() const { return a; }
//	T2 second() const { return b; }
//	Pair(const T1& aval, const T2& bval) :a(aval), b(bval) { }
//	Pair() {}
//};
//
//template <class T1, class T2>
//T1& Pair<T1, T2>::first()
//{
//	return a;
//}
//
//template <class T1, class T2>
//T2& Pair<T1, T2>::second()
//{
//	return b;
//}
//
//int main()
//{
//	using std::cout;
//	using std::endl;
//	using std::string;
//	Pair<string, int> ratings[4] =
//	{
//		Pair<string, int>("The Purpled Duck", 5),
//		Pair<string, int>("Jaquie's Frisco AI Fresco", 4),
//		Pair<string, int>("Cafe Souffle", 5),
//		Pair<string, int>("Bertie's Eats", 3)
//	};
//
//	int joints = sizeof(ratings) / sizeof(Pair<string, int>);
//	cout << "Rating:\t Eatery\n";
//	for (int i = 0; i < joints; i++)
//	{
//		cout << ratings[i].second() << ":\t "
//			 << ratings[i].first() << endl;
//	}
//	cout << "Oops! Revised rating:\n";
//	ratings[3].first() = "Bertie's Fab Eats";
//	ratings[3].second() = 6;
//	cout << ratings[3].second() << ":\t "
//		 << ratings[3].first() << endl;
//
//	return 0;
//}

// tempmemb.cpp -- template members
//#include <iostream>
//
//using std::cout;
//using std::endl;
//
//template <typename T>
//class beta
//{
//private:
//	template <typename V>	// nested template class member
//	class hold
//	{
//	private:
//		V val;
//	public:
//		hold(V v = 0) :val(v) { }
//		void show() const { cout << val << endl; }
//		V Value() const { return val; }
//	};
//	hold<T> q;		// template object
//	hold<int> n;	// template object
//public:
//	beta(T t, int i) :q(t), n(i) { }
//	template<typename U>	// template method
//	U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
//	void Show() const { q.show(); n.show(); }
//};
//
//int main()
//{
//	beta<double> guy(3.5, 3);
//	cout << "T was set to double\n";
//	guy.Show();
//	cout << "V was set to T, which is double, then V was set to int\n";
//	cout << guy.blab(10, 2.3) << endl;
//	cout << "U was set to int\n";
//	cout << guy.blab(10.0, 2.3) << endl;
//	cout << "U was set to double\n";
//	cout << "Done\n";
//
//	return 0;
//}

//#include <iostream>
//
//template <typename T>
//class beta
//{
//private:
//    template <typename V> // declaration
//    class hold;
//    hold<T> q;
//    hold<int> n;
//public:
//    beta(T t, int i) : q(t), n(i) { }
//    template<typename U> // declaration
//    U blab(U u, T t);
//    void Show() const { q.show(); n.show(); }
//};
//
//// member definition
//template <typename T>
//template<typename V>
//class beta<T>::hold
//{
//private:
//    V val;
//public:
//    hold(V v = 0) :val(v) {}
//    void show() const { std::cout << val << std::endl; }
//    V value() const { return val; }
//};
//
//// member definition
//template <typename T>
//template<typename U>
//U beta<T>::blab(U u, T t)
//{
//    return (n.value() + q.value()) * u / t;
//}
//
//int main()
//{
//    beta<double> guy(3.5, 3);
//    std::cout << "T was set to double\n";
//    guy.Show();
//
//    return 0;
//}

// tempparm.cpp - templates as parameters
//#include <iostream>
//#include "test_0307.h"
//
//template <template <typename T> class Thing>
//class Grab
//{
//private:
//	Thing<int> s1;
//	Thing<double> s2;
//public:
//	Grab() {};
//	// assumes the thing class has push() and pop() members
//	bool push(int a, double x) { return s1.push(a) && s2.push(x); }
//	bool pop(int& a, double& x) { return s1.pop(a) && s2.pop(x); }
//};
//
//int main()
//{
//	using std::cout;
//	using std::cin;
//	using std::endl;
//	Grab<Stack> nebula;
//// Stack must match template <typename T> class thing
//	int ni;
//	double nb;
//	cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";
//	while (cin >> ni >> nb && ni > 0 && nb > 0)
//	{
//		if (!nebula.push(ni, nb))
//		{
//			break;
//		}
//	}
//
//	while (nebula.pop(ni, nb))
//	{
//		cout << ni << ", " << nb << endl;
//	}
//	cout << "Done.\n";
//
//	return 0;
//}

// frnd2tmp.cpp -- template class with non-template friends
//#include <iostream>
//using std::cout;
//using std::endl;
//
//template <typename T>
//class HasFriend
//{
//public:
//	HasFriend(const T& i) :item(i) { ct++; }
//	~HasFriend() { ct--; }
//	friend void counts();
//	friend void reports(HasFriend<T>&);	// template parameter
//
//private:
//	T item;
//	static int ct;
//};
//
//// each specialization has its own static data member
//template <typename T>
//int HasFriend<T>::ct = 0;
//
//// non-template friend to all HasFriend<T> classes
//void counts()
//{
//	cout << "int count: " << HasFriend<int>::ct << "; ";
//	cout << "double count: " << HasFriend<double>::ct << endl;
//}
//
//// non-template friend to the HasFriend<int> class 
//void reports(HasFriend<int>& hf)
//{
//	cout << "HasFriend<int>: " << hf.item << endl;
//}
//
//// non-template friend to the HasFriend<double> class
//void reports(HasFriend<double>& hf)
//{
//	cout << "HasFriend<double>: " << hf.item << endl;
//}
//
//int main()
//{
//	cout << "No objects declared: ";
//	counts();
//	HasFriend<int> hfi1(10);
//	cout << "After hfil declared: ";
//	counts();
//	HasFriend<int> hfi2(20);
//	cout << "After hfi2 declared: ";
//	counts();
//	HasFriend<double> hfdb(10.5);
//	cout << "After hfdb declared: ";
//	counts();
//	reports(hfi1);
//	reports(hfi2);
//	reports(hfdb);
//
//	return 0;
//}

// tmp2tmp.cpp -- template friends to a template class
//#include <iostream>
//using std::cout;
//using std::endl;
//
//// template prototypes
//template<typename T> void counts();
//template<typename T> void report(T&);
//
//// template class
//template <typename TT>
//class HasFriendT
//{
//private:
//	TT item;
//	static int ct;
//public:
//	HasFriendT(const TT& i) :item(i) { ct++; }
//	~HasFriendT() { ct--; }
//	friend void counts<TT>();
//	friend void report<>(HasFriendT<TT>&);
//};
//
//template <typename T>
//int HasFriendT<T>::ct = 0;
//
//// template friend functions definitions
//template <typename T>
//void counts()
//{
//	cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
//	cout << "template counts(): " << HasFriendT<T>::ct << endl;
//}
//
//template <typename T>
//void report(T& hf)
//{
//	cout << hf.item << endl;
//}
//
//int main()
//{
//	counts<int>();
//	HasFriendT<int> hfi1(10);
//	HasFriendT<int> hfi2(20);
//	HasFriendT<double> hfdb(10.5);
//	report(hfi1);	// generate report(HasFriend<int>&)
//	report(hfi2);
//	report(hfdb);
//	cout << "counts<int>() output:\n";
//	counts<int>();
//	cout << "counts<double>() output:\n";
//	counts<double>();
//
//	return 0;
//}

// manyfrnd.cpp -- unbound template friend to a template class
//#include <iostream>
//using std::cout;
//using std::endl;
//
//template <typename T>
//class ManyFriend
//{
//private:
//	T item;
//public:
//	ManyFriend(const T& i) :item(i) {}
//	template <typename C, typename D> friend void show2(C&, D&);
//};
//
//template <typename C, typename D> void show2(C& c, D& d)
//{
//	cout << c.item << ", " << d.item << endl;
//}
//
//int main()
//{
//	ManyFriend<int> hfi1(10);
//	ManyFriend<int> hfi2(20);
//	ManyFriend<double> hfdb(10.5);
//	cout << "hfi1, hfi2: ";
//	show2(hfi1, hfi2);
//	cout << "hfdb, hfi2: ";
//	show2(hfdb, hfi2);
//
//	return 0;
//}